import { ErrorCode } from "../src/config/ErrorCode";
import { GameConfig } from "../src/config/GameConfig";
import { ServerConfig } from "../src/config/ServerConfig";
import { Logger } from "../src/engine/utils/Logger";
import { Md5Helper } from "../src/engine/utils/Md5Helper";
import { WebUtil } from "../src/engine/utils/WebUtil";
import { ResponseModel } from "../src/model/ResponseModel";
import { ServerManager } from "../src/server/ServerManager";
import { AccountDao } from "./dao/AccountDao";
import { UserDao } from "../src/dao/UserDao";
import { WechatSdkManager } from "./WechatSdkManager";
import { UserModel } from "../src/model/UserModel";
import { Base64Helper } from "../src/engine/utils/Base64Helper";
import RandomUtil from "../src/engine/utils/RandomUtil";
import { HttpUtil } from "../src/engine/utils/HttpUtil";
import { AccountModel } from "./model/AccountModel";
import { Config } from "../src/config/Config";

const request = require('request');
const crypto = require("crypto");

const routerMap = {
    updateServerStatus: "/updateServerStatus",
    register: "/register",
    account_auth: "/account_auth",
    wechat_auth: "/wechat_auth",
    phone_auth: "/phone_auth",
    wechat_account_auth: "/wechat_account_auth",
    bindPhone: "/bindPhone",
    phoneRegister: "/phoneRegister",
    getPhoneCode: "/getPhoneCode",
    reset_pass: "/reset_pass"
}

export class AccountReqHandler {

    public static instance: AccountReqHandler = new AccountReqHandler();


    public init(app) {
        for (const key in routerMap) {
            app.use(routerMap[key], this.onBaseRoot.bind(this))
        }
    }

    private onBaseRoot(req, resp) {
        try {
            let ip: string = WebUtil.getIpByExpressReq(req);
            Logger.log("onBaseRoot==", ip, req.baseUrl)
            if (req.baseUrl == routerMap.updateServerStatus) {
                ServerConfig.initConfig(ServerConfig.nowServerConfig.nowPort)
                resp.end("success");
            }
            else if (req.baseUrl == routerMap.register) {
                this.checkBody(ip, req, resp, this.on_register.bind(this))
            }
            else if (req.baseUrl == routerMap.account_auth) {
                this.checkBody(ip, req, resp, this.on_account_auth.bind(this))
            }
            else if (req.baseUrl == routerMap.wechat_account_auth) {
                this.checkBody(ip, req, resp, this.on_wechat_account_auth.bind(this))
            }
            else if (req.baseUrl == routerMap.wechat_auth) {
                this.checkBody(ip, req, resp, this.on_wechat_auth.bind(this))
            }
            else if (req.baseUrl == routerMap.bindPhone) {
                this.checkBody(ip, req, resp, this.on_bindPhone.bind(this))
            }
            else if (req.baseUrl == routerMap.phoneRegister) {
                this.checkBody(ip, req, resp, this.on_phoneRegister.bind(this))
            }
            else if (req.baseUrl == routerMap.getPhoneCode) {
                this.checkBody(ip, req, resp, this.on_getPhoneCode.bind(this))
            }
            else if (req.baseUrl == routerMap.phone_auth) {
                this.checkBody(ip, req, resp, this.on_phone_auth.bind(this))
            }
            else if (req.baseUrl == routerMap.reset_pass) {
                this.checkBody(ip, req, resp, this.on_reset_pass.bind(this))
            }

        } catch (error) {
            Logger.warn("onBaseRoot error", error);
        }
    }

    private checkQuery(ip: string, req, resp, callback: Function) {
        if (req.query) {
            try {
                let jsonObj = req.query
                let k: string = jsonObj["k"];
                let dataStr: string = jsonObj["data"]
                if (k == Md5Helper.getMd5_encrypt(dataStr)) {
                    let data: object = JSON.parse(dataStr)
                    callback && callback(req, resp, data, ip);
                }
                else {
                    Logger.error("收到非法Http请求 key", ip, jsonObj)
                    resp.end();
                }
            } catch (error) {
                Logger.error("收到非法Http请求query", ip, req.query, error)
                resp.end();
            }
        }
        else {
            resp.end();
        }
    }

    private checkBody(ip: string, req, resp, callback: Function) {
        if (req.body) {
            try {
                let jsonObj = JSON.parse(req.body);
                let k: string = jsonObj["k"];
                let data: object = jsonObj["data"]
                if (k == Md5Helper.getMd5_encrypt(JSON.stringify(data))) {
                    callback && callback(req, resp, data, ip);
                }
                else {
                    Logger.error("收到非法Http请求 key", ip, req.body)
                    resp.end();
                }
            } catch (error) {
                Logger.error("收到非法Http请求body", ip, req.body, error)
                resp.end();
            }
        }
        else {
            resp.end();
        }
    }

    private async on_phoneRegister(req, resp, data: object, ip) {
        let phone: string = data["phone"]
        let code: string = data["code"]
        let pass: string = data["pass"]
        let channel: number = data["channel"]
        let os: string = data["os"]
        let phone_type: string = data["phone_type"]
        let bundle_name: string = data["bundle_name"]
        let system_version: string = data["system_version"]
        Logger.log("on_phoneRegister==", data)
        if (AccountModel.phoneCodeMap.get(phone) == code) {
            let accountResult: object = await AccountDao.get_account_info(phone)
            if (accountResult) {
                resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "该手机已注册账号")))
            } else {
                accountResult = await AccountDao.getAccountByPhone(phone)
                if (accountResult) {
                    resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "该手机已绑定微信账号")))
                } else {
                    let token: string = Md5Helper.createToken(phone)
                    let isSuc: boolean = await AccountDao.create_account(phone, pass, GameConfig.Account_Type.Phone, token,
                        GameConfig.Status_Type.Normal, ip, phone, channel, os, phone_type, bundle_name, system_version);
                        Logger.log("on_phoneRegister=222=", isSuc)
                    if (isSuc) {
                        let data: object = {
                            "account": phone,
                            "token": token,
                            "nickname": phone,
                            "sex": 1,
                            "headimgurl": "",
                            "account_type": GameConfig.Account_Type.Phone
                        }
                        // data["server"] = await this.getHallServer(unionid)
                        resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Suc, "", data)))
                    }
                }
            }
        }
        else{
            resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "验证码不对")))
        }
    }
    

    private async on_register(req, resp, data: object, ip) {
        Logger.log("on_register=", data, ip)
        let account: string = data["account"]
        account = Base64Helper.encode(account)
        let password: string = data["password"]
        let channel: number = data["channel"]
        let os: string = data["os"]
        let phone_type: string = data["phone_type"]
        let bundle_name: string = data["bundle_name"]
        let system_version: string = data["system_version"]

        let isExist = await AccountDao.is_account_exist(account)
        // Logger.log("on_register===isExist=", isExist)
        if (isExist) {
            resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "已存在账号")))
        } else {
            let token: string = Md5Helper.createToken(account)
            let isSuc: boolean = await AccountDao.create_account(account, password, GameConfig.Account_Type.Account, token,
                GameConfig.Status_Type.Normal, ip, Base64Helper.decode(account), channel, os, phone_type, bundle_name, system_version);

            if (isSuc) {
                let data: object = {
                    "account": Base64Helper.decode(account),
                    "token": token,
                    "nickname": Base64Helper.decode(account),
                    "sex": 1,
                    "headimgurl": "",
                    "account_type": GameConfig.Account_Type.Account
                }
                // data["server"] = await this.getHallServer(unionid)
                resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Suc, "", data)))

            } else {
                resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "数据库错误，创建账号失败")))
            }
        }
    }

    private async on_account_auth(req, resp, data: object, ip) {
        Logger.log("on_account_auth=", data, ip)
        let account: string = data["account"]
        account = Base64Helper.encode(account)
        let password: string = data["password"]
        let channel: number = data["channel"]
        let os: string = data["os"]
        let phone_type: string = data["phone_type"]
        let bundle_name: string = data["bundle_name"]
        let system_version: string = data["system_version"]

        let accountResult: object = await AccountDao.get_account_info(account)
        Logger.log("on_account_auth=2222===", accountResult)
        if (accountResult) {
            if (password == accountResult["password"]) {
                if (accountResult["status"] == GameConfig.Status_Type.FengJin) {
                    resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "用户被冻结")))
                } else {
                    let token: string = Md5Helper.createToken(account)
                    let isUpdateSuc: boolean = await AccountDao.update_login(account, token, ip, accountResult["nick_name"], channel, os, phone_type, bundle_name, system_version);
                    if (isUpdateSuc) {
                        let respData: object = {
                            "account": Base64Helper.decode(account),
                            "token": token,
                            "nickname": accountResult["nick_name"],
                            "sex": accountResult["sex"],
                            "headimgurl": accountResult["headimgurl"],
                            "account_type": GameConfig.Account_Type.Account
                        }
                        // Logger.log("on_account_auth=3333===", isUpdateSuc)
                        resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Suc, "", respData)))
                    }
                    else {
                        resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Db_Error, "数据库错误")))
                    }
                }

            } else {
                Logger.log("on_account_auth账号密码不对", password, accountResult["password"])
                resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.LoginError_NoPass, "登录密码错误")))
            }
        } else {
            resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.LoginError_NoUser, "不存在该用户")))
        }
    }

    public async on_wechat_account_auth(req, resp, data: object, ip) {
        Logger.log("on_wechat_account_auth=", data, ip)
        let account: string = data["account"]
        let password: string = data["password"]
        let channel: number = data["channel"]
        let os: string = data["os"]
        let phone_type: string = data["phone_type"]
        let bundle_name: string = data["bundle_name"]
        let system_version: string = data["system_version"]

        let accountResult: object = await AccountDao.get_account_info(account)
        if (accountResult) {
            if (password == accountResult["password"]) {
                if (accountResult["status"] == GameConfig.Status_Type.FengJin) {
                    resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "用户被冻结")))
                } else {
                    let token: string = Md5Helper.createToken(account)
                    let isUpdateSuc: boolean = await AccountDao.update_login(account, token, ip, accountResult["nick_name"], channel, os, phone_type, bundle_name, system_version);
                    if (isUpdateSuc) {
                        let respData: object = {
                            "account": account,
                            "token": token,
                            "nickname": accountResult["nick_name"],
                            "sex": accountResult["sex"],
                            "headimgurl": accountResult["headimgurl"],
                            "account_type": GameConfig.Account_Type.Wechat,
                            "phone": accountResult["phone"],
                        }
                        // Logger.log("on_account_auth=3333===", isUpdateSuc)
                        resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Suc, "", respData)))
                    }
                    else {
                        resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Db_Error, "数据库错误")))
                    }
                }

            } else {
                Logger.log("on_account_auth账号密码不对", password, accountResult["password"])
                resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.LoginError_NoPass, "登录密码错误")))
            }
        } else {
            resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.LoginError_NoUser, "不存在该用户")))
        }
    }

    private async on_wechat_auth(req, resp, data: object, ip) {
        Logger.log("on_wechat_auth=", data, ip)
        let code: string = data["code"]
        let channel: number = data["channel"]
        let os: string = data["os"]
        let phone_type: string = data["phone_type"]
        let bundle_name: string = data["bundle_name"]
        let system_version: string = data["system_version"]

        WechatSdkManager.instance.get_access_token(code, (respData) => {
            if (respData.status == 200) {
                Logger.log("get_access_token===resp=", respData.data)
                if (respData.data["errcode"] && respData.data["errmsg"]) {
                    resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, respData.data["errmsg"])))
                } else {
                    let openid: string = respData.data["openid"]
                    let access_token: string = respData.data["access_token"]
                    WechatSdkManager.instance.get_userinfo(access_token, openid, async (respData) => {
                        if (respData.status == 200) {
                            Logger.log("get_userinfo===resp=", respData.data)
                            if (respData.data["errcode"] && respData.data["errmsg"]) {
                                resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, respData.data["errmsg"])))
                            }
                            else {
                                let unionid: string = respData.data["unionid"]
                                let nickname: string = respData.data["nickname"]
                                let sex: number = respData.data["sex"]
                                let headimgurl: string = respData.data["headimgurl"]
                                let token: string = Md5Helper.createToken(unionid)
                                let accountResult: object = await AccountDao.get_account_info(unionid)
                                let phone: string = null
                                let isSuc: boolean = true
                                if (accountResult) {
                                    phone = accountResult["phone"]
                                    isSuc = await AccountDao.update_login(unionid, token, ip, nickname, channel, os, phone_type, bundle_name, system_version, sex, headimgurl);

                                } else {
                                    isSuc = await AccountDao.create_account(unionid, "123456", GameConfig.Account_Type.Wechat, token,
                                        GameConfig.Status_Type.Normal, ip, nickname, channel, os, phone_type, bundle_name, system_version, sex, headimgurl);

                                }
                                if (isSuc) {
                                    let data: object = {
                                        "account": unionid,
                                        "token": token,
                                        "nickname": nickname,
                                        "sex": sex,
                                        "headimgurl": headimgurl,
                                        "account_type": GameConfig.Account_Type.Wechat,
                                        "phone": phone,
                                    }
                                    // data["server"] = await this.getHallServer(unionid)
                                    resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Suc, "", data)))
                                } else {
                                    resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Db_Error, "账号数据库操作失败")))
                                }
                            }

                        } else {
                            resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, respData.statusText)))
                        }
                    })
                }
            } else {
                Logger.log("get_access_token===resp==error=", respData.statusText)
                resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, respData.statusText)))
            }
        })
    }

    private async on_getPhoneCode(req, resp, data: object, ip) {
        let phone: string = data["phone"]
        let code: string = RandomUtil.nextInt(100000, 999999) + ""
        let content: string = "【广东潮聚】您的验证码是" + code
        let username: string = "8041SKoR_1"
        let password: string = "xmtrp7ky"
        // if (Config.environment == Config.EnvironmentType.xj) {
        //     content = "【闲聚】您的验证码是" + code
        //     username = "8042HDfP_1"
        //     password = "aspbybz4"
        // }
        let reqData = {
            "username": username,
            "password": password,
            "isLongSms": 0,
            "method": "sendSMS",
            "mobile": phone,
            "extenno": "0",
            "priorityFlag": 0,
            "content": content
        };
        AccountModel.phoneCodeMap.set(phone, code)
        Logger.log("on_getPhoneCode==", phone, code)
        HttpUtil.request_by_form("http://sms.clsoftware.com:9090/servlet/UserServiceAPI", reqData, (respData: object) => {
            Logger.log("on_getPhoneCode==", reqData, respData["data"])
            resp.end(JSON.stringify(ResponseModel.create()))
        })
    }

    private async on_bindPhone(req, resp, data: object, ip) {
        let account: string = data["account"]
        let phone: string = data["phone"]
        let code: string = data["code"]
        let pass: string = data["pass"]
        let accountResult: object = await AccountDao.get_account_info(account)
        if (accountResult) {
            if (accountResult["phone"] && accountResult["phone"] != "") {
                resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "该账号已经绑定过手机")))
            }
            else {
                if (AccountModel.phoneCodeMap.get(phone) == code) {
                    accountResult = await AccountDao.get_account_info(phone)
                    if(accountResult){
                        resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "该手机已经已绑定其他账号")))
                    }else{
                        let isSuc: boolean = await AccountDao.bindPhone(account, phone, pass)
                        if (isSuc) {
                            resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Suc, "绑定成功")))
                        }
                        else {
                            resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "绑定手机保存失败")))
                        }
                    }
                } else {
                    resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "验证码不对")))
                }
            }
        } else {
            resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "账号不存在")))
        }
    }

    private async on_phone_auth(req, resp, data: object, ip) {
        let phone: string = data["phone"]
        let password: string = data["password"]
        let accountResult: object = await AccountDao.getAccountByPhone(phone)
        if(!accountResult){
            accountResult =  await AccountDao.get_account_info(phone)
        }
        if (accountResult) {
            Logger.log("on_phone_auth==", data, accountResult)
            if (accountResult["password"] == password) {
                if (accountResult["status"] == GameConfig.Status_Type.FengJin) {
                    resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "用户被冻结")))
                } else {
                    let channel: number = data["channel"]
                    let os: string = data["os"]
                    let phone_type: string = data["phone_type"]
                    let bundle_name: string = data["bundle_name"]
                    let system_version: string = data["system_version"]

                    let account: string = accountResult["account"]
                    let token: string = Md5Helper.createToken(account)
                    let isSuc: boolean = await AccountDao.update_login(account, token, ip, accountResult["nick_name"],
                        channel, os, phone_type, bundle_name, system_version, accountResult["sex"], accountResult["headimgurl"]);
                    if (isSuc) {
                        let respData: object = {
                            "account": account,
                            "token": token,
                            "nickname": accountResult["nick_name"],
                            "sex": accountResult["sex"],
                            "headimgurl": accountResult["headimgurl"],
                            "account_type": GameConfig.Account_Type.Wechat,
                            "phone": phone,
                        }
                        resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Suc, "", respData)))
                    }
                    else {
                        resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "登录保存用户信息失败")))
                    }

                }
            }
            else {
                resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "密码不对")))
            }
        } else {
            resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "账号不存在")))
        }
    }

    private async on_reset_pass(req, resp, data: object, ip) {
        let phone: string = data["phone"]
        let password: string = data["password"]
        let code: string = data["code"]
        let accountResult: object = await AccountDao.getAccountByPhone(phone)
        if (accountResult) {
            Logger.log("on_reset_pass==", data, accountResult)
            if (accountResult["status"] == GameConfig.Status_Type.FengJin) {
                resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "用户被冻结")))
            } else {
                if (AccountModel.phoneCodeMap.get(phone) == code) {
                    let isSuc: boolean = await AccountDao.reset_pass(phone, password);
                    if (isSuc) {
                        resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Suc, "")))
                    }
                    else {
                        resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "重置密码保存用户信息失败")))
                    }
                } else {
                    resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "验证码不对")))
                }
            }
        } else {
            resp.end(JSON.stringify(ResponseModel.create(ErrorCode.Code.Fail, "账号不存在")))
        }
    }

    private async getHallServer(account: string) {
        let resultServerConfig: ServerConfig = await ServerManager.instance.is_in_server(account)
        if (!resultServerConfig) {
            resultServerConfig = ServerConfig.randomHallServer()
        }
        return resultServerConfig;

    }




}